from django.shortcuts import render,HttpResponse,redirect
from .models import  *

# Create your views here.
def exec_task(servers,mod,args):
    import json
    import shutil
    # 使用了命名元组
    from collections import namedtuple
    # DataLoader用于解析yaml/json/ini文件
    from ansible.parsing.dataloader import DataLoader
    # VariableManager用于分析ansible用到的变量
    from ansible.vars.manager import VariableManager
    # InventoryManager用于分析主机文件
    from ansible.inventory.manager import InventoryManager
    from ansible.playbook.play import Play
    # task_queue_manager管理任务队列
    from ansible.executor.task_queue_manager import TaskQueueManager
    # 回调函数
    from ansible.plugins.callback import CallbackBase
    # 管理常量(不会变化的数据)
    import ansible.constants as C

    # 可以用来自定义回调函数的返回值（为了方便，可以去掉）
    # class ResultCallback(CallbackBase):
    # """A sample callback plugin used for performing an action as results come in
    #
    # If you want to collect all results into a single object for processing at
    # the end of the execution, look into utilizing the ``json`` callback plugin
    # or writing your own custom callback plugin
    # """
    # def v2_runner_on_ok(self, result, **kwargs):
    # """Print a json representation of the result
    #
    # This method could store the result in an instance attribute for retrieval later
    # """
    # host = result._host
    # print(json.dumps({host.name: result._result}, indent=4))

    # since API is constructed for CLI it expects certain options to always be set, named tuple 'fakes' the args parsing options object
    # connection有三个选择local/ssh/smart
    # local表示在本地执行，ssh表示通过ssh协议执行,smart可以自动识别本地还是远程
    Options = namedtuple('Options',
                         ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check',
                          'diff'])
    options = Options(connection='smart', module_path=['/to/mymodules'], forks=10, become=None, become_method=None,
                      become_user=None, check=False, diff=False)

    # initialize needed objects
    loader = DataLoader() # Takes care of finding and reading yaml, json and ini files
    # passwords = dict(vault_pass='secret')
    # 用于存储加密密码，远程连接密码等（我们可以置空，不做密码加密处理）
    passwords = dict()

    # Instantiate our ResultCallback for handling results as they come in. Ansible expects this to be one of its main display outlets
    # 不使用CallbackBase类，使用默认输出
    # results_callback = ResultCallback()

    # create inventory, use path to host config file as source or hosts in a comma separated string
    # inventory = InventoryManager(loader=loader, sources='localhost,')
    # 使用自定义的主机清单
    # inventory = InventoryManager(loader=loader, sources=['/root/ansible/hosts'])
    inventory = InventoryManager(loader=loader, sources=['/root/达内Python/ansi_project/myansible/ansicfg/dhosts.py'])

    # variable manager takes care of merging all the different sources to give you a unifed view of variables available in each context
    variable_manager = VariableManager(loader=loader, inventory=inventory)

    # create datastructure that represents our play, including tasks, this is basically what our YAML loader does internally.
    play_source = dict(
        name="Ansible Play",  # Play名称
        hosts= servers,  # 在哪些主机上执行命令
        gather_facts='no',  # 不收集主机信息
        tasks=[
            # 以下是执行的命令
            # dict(action=dict(module='shell', args='ls'), register='shell_out'),
            dict(action=dict(module=mod, args=args), register='shell_out'),
            # dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}')))
            dict(action=dict(module='debug', args=dict(msg='{{shell_out}}')))
        ]
    )

    # Create play object, playbook objects use .load instead of init or new methods,# this will also automatically create the task objects from the info provided in play_source
    play = Play().load(play_source, variable_manager=variable_manager, loader=loader)

    # Run it - instantiate task queue manager, which takes care of forking and setting up all objects to iterate over host list and tasks
    tqm = None
    try:
        tqm = TaskQueueManager(
            inventory=inventory,
            variable_manager=variable_manager,
            loader=loader,
            options=options,
            passwords=passwords,
            # stdout_callback=results_callback, # Use our custom callback instead of the ``default`` callback plugin, which prints to stdout
        )
        result = tqm.run(play)  # most interesting data for a play is actually sent to the callback's methods
    finally:
        # we always need to cleanup child procs and the structres we use to communicate with them
        if tqm is not None:
            tqm.cleanup()

        # Remove ansible tmpdir
        shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)


def index(request):
    return render(request,'index.html')

def mainpage(request):
    return render(request,'mainpage.html')

def addhosts(request):
    if request.method == 'POST':
        group = request.POST.get('group')
        host = request.POST.get('host')
        ip = request.POST.get('ip')
        g = HostGroup.objects.get_or_create(group_name=group)[0]
        g.host_set.get_or_create(hostname=host,ipaddr=ip)

    groups = HostGroup.objects.all()
    context = {'groups':groups}
    return render(request,'addhost.html',context)

def addmodules(request):
    if request.method == 'POST':
        mod = request.POST.get('mod_name')
        arg = request.POST.get('arg')
        if mod and arg:
            m = AnsibleModule.objects.get_or_create(mod_name=mod)[0]
            m.modulearg_set.get_or_create(arg_text=arg)

    mods = AnsibleModule.objects.all()
    return render(request,'addmodules.html',{'mods':mods})

def tasks(request):
    if request.method == 'POST':
        server = request.POST.get('ip')
        if not server:
            server = request.POST.get('group')
        mod = request.POST.get('mod')
        args = request.POST.get('arg')
        exec_task(server,mod,args)

    hosts = Host.objects.all()
    groups = HostGroup.objects.all()
    mods = AnsibleModule.objects.all()
    context = {'hosts':hosts,'groups':groups,'mods':mods}
    return render(request,'tasks.html',context)

def rmarg(request,arg_id):
    a = ModuleArg.objects.get(id=arg_id)
    a.delete()
    return redirect('addmodules')